/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.nio.channels;

import java.io.IOException;
import java.nio.channels.spi.AbstractInterruptibleChannel;
import java.nio.channels.spi.SelectorProvider;


/**
 * 一种可以通过选择器多路复用的信道。
 *
 * <p> 为了与选择器一起使用，必须首先通过register(Selector,int,Object)方法注册此类的实例。
 * 此方法返回一个新的SelectionKey对象，该对象表示通道在选择器中的注册。
 *
 * <p> 一旦使用选择器注册，通道将保持注册状态，直到取消注册。
 * 这包括释放选择器分配给通道的所有资源。
 *
 * <p> 不能直接注销通道；
 * 相反，必须取消代表其注册的键。
 * 取消键请求在选择器的下一个选择操作期间取消注册通道。
 * 可以通过调用键的cancel方法显式取消键。
 * 当通道关闭时，通道的所有键都会被隐式取消，
 * 无论是通过调用它的close方法还是通过中断在通道上I/O操作中阻塞的线程。
 *
 * <p> 如果选择器本身关闭，则信道将被注销，代表其注册的密钥将失效，不再延迟。
 *
 * <p> 一个频道最多可以用任何特定选择器注册一次。
 *
 * <p> 通道是否注册到一个或多个选择器可以通过调用isRegistered方法来确定。
 *
 * <p> 多个并发线程可以安全地使用可选通道。 </p>
 *
 *
 * <a name="bm"></a>
 * <h2>阻塞方式</h2>
 *
 * 可选择的信道处于阻塞模式或非阻塞模式。
 * 在阻塞模式下，通道上调用的每个I/O操作都将阻塞，直到完成。
 * 在非阻塞模式下，I/O操作永远不会阻塞，传输的字节数可能少于请求的字节数，或者根本就没有字节数。
 * 可选择通道的阻塞模式可以通过调用其isBlocking方法来确定。
 *
 * <p> 新创建的可选频道始终处于阻塞状态模式。
 * 非阻塞模式与基于选择器的多路复用一起使用最为有用。
 * 在向选择器注册之前，必须将通道置于非阻塞模式，并且在取消注册之前不能返回到阻塞模式。
 *
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 *
 * @see SelectionKey
 * @see Selector
 */

public abstract class SelectableChannel
    extends AbstractInterruptibleChannel
    implements Channel
{

    /**
     * 初始化一个新的实例
     */
    protected SelectableChannel() { }

    /**
     * 返回创建此频道的提供程序。
     *
     * @return  The provider that created this channel
     */
    public abstract SelectorProvider provider();

    /**
     * 返回标识此通道支持的操作的操作集。
     * 在这个整数值中设置的位正好表示对这个通道有效的操作。
     * 对于给定的具体的通道类，此方法始终返回相同的值。
     *
     * @return  The valid-operation set
     */
    public abstract int validOps();

    //  内部状态
    //   keySet, 可以是空的，但不会为null，通常是一个小数组
    //   boolean isRegistered, 由keyset保护
    //   regLock, 防止重复注册的锁对象
    //   boolean isBlocking, 由regLock保护

    /**
     * 指示此频道当前是否已注册到任何选择器。新创建的频道未注册。
     *
     * <p> 在取消注册的通道中，由于密钥在取消注册后的某个时间内被取消，因此可能会保留密钥。
     * 通道也可以在关闭后的一段时间内保持注册状态。</p>
     *
     * @return <tt>true</tt> if, and only if, this channel is registered
     */
    public abstract boolean isRegistered();
    //
    // sync(keySet) { return isRegistered; }

    /**
     * 检索表示频道注册到给定的选择器的密钥。
     *
     * @param   sel
     *          The selector
     *
     * @return  The key returned when this channel was last registered with the
     *          given selector, or <tt>null</tt> if this channel is not
     *          currently registered with that selector
     */
    public abstract SelectionKey keyFor(Selector sel);
    //
    // sync(keySet) { return findKey(sel); }

    /**
     * 用给定的选择器注册此通道，返回selectionkey。
     *
     * <p> 如果此频道已经使用给定的选择器注册，则返回表示该注册的选择键。
     * 键的interest set将被更改为ops，就像调用SelectionKey.interestOps(int)方法一样。
     * 如果att参数不为null，则键的attachments将被设置为该值。
     * 如果密钥已被取消，则将引发CancelledKeyException。
     *
     * <p> 否则，此频道尚未向给定的选择器注册，因此它被注册，生成的新密钥被返回。
     * key的初始interest set是ops，它的attachment是att。
     *
     * <p> 可以随时调用此方法。
     * 如果在对另一个该方法或configureBlocking方法的调用时调用此方法，则它将首先阻塞，直到另一个操作完成。
     * 然后，此方法将在选择器的密钥集上同步，因此，
     * 如果与涉及同一选择器的另一个注册或选择操作同时调用，则可能会阻塞。</p>
     *
     * <p>如果此通道在操作过程中关闭，则此方法返回的密钥将被取消，因此将无效。</p>
     *
     * @param  sel
     *         The selector with which this channel is to be registered
     *
     * @param  ops
     *         The interest set for the resulting key
     *
     * @param  att
     *         The attachment for the resulting key; may be <tt>null</tt>
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  ClosedSelectorException
     *          If the selector is closed
     *
     * @throws  IllegalBlockingModeException
     *          If this channel is in blocking mode
     *
     * @throws  IllegalSelectorException
     *          If this channel was not created by the same provider
     *          as the given selector
     *
     * @throws  CancelledKeyException
     *          If this channel is currently registered with the given selector
     *          but the corresponding key has already been cancelled
     *
     * @throws  IllegalArgumentException
     *          If a bit in the <tt>ops</tt> set does not correspond to an
     *          operation that is supported by this channel, that is, if
     *          {@code set & ~validOps() != 0}
     *
     * @return  A key representing the registration of this channel with
     *          the given selector
     */
    public abstract SelectionKey register(Selector sel, int ops, Object att)
        throws ClosedChannelException;
    //
    // sync(regLock) {
    //   sync(keySet) { look for selector }
    //   if (channel found) { set interest ops -- may block in selector;
    //                        return key; }
    //   create new key -- may block somewhere in selector;
    //   sync(keySet) { add key; }
    //   attach(attachment);
    //   return key;
    // }

    /**
     * 用给定的选择器注册此通道，返回selectionkey。
     *
     * <p> 这种调用的形式
     *
     * <blockquote><tt>sc.register(sel, ops)</tt></blockquote>
     *
     * 与下面的调用相同
     *
     * <blockquote><tt>sc.{@link
     * #register(java.nio.channels.Selector,int,java.lang.Object)
     * register}(sel, ops, null)</tt></blockquote>
     *
     * @param  sel
     *         The selector with which this channel is to be registered
     *
     * @param  ops
     *         The interest set for the resulting key
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  ClosedSelectorException
     *          If the selector is closed
     *
     * @throws  IllegalBlockingModeException
     *          If this channel is in blocking mode
     *
     * @throws  IllegalSelectorException
     *          If this channel was not created by the same provider
     *          as the given selector
     *
     * @throws  CancelledKeyException
     *          If this channel is currently registered with the given selector
     *          but the corresponding key has already been cancelled
     *
     * @throws  IllegalArgumentException
     *          If a bit in <tt>ops</tt> does not correspond to an operation
     *          that is supported by this channel, that is, if {@code set &
     *          ~validOps() != 0}
     *
     * @return  A key representing the registration of this channel with
     *          the given selector
     */
    public final SelectionKey register(Selector sel, int ops)
        throws ClosedChannelException
    {
        return register(sel, ops, null);
    }

    /**
     * 通道阻塞模式调整。
     *
     * <p> 如果这个通道是用一个或多个选择器注册的，
     * 那么试图将它置于阻塞模式将导致抛出一个IllegalBlockingModeException。
     *
     * <p> 可以随时调用此方法。
     * 新的阻塞模式只会影响在此方法之后启动的I/O操作返回。
     * 为有些实现可能需要阻塞，直到所有挂起的I/O操作完成。
     *
     * <p> 如果在对该方法或register(Selector, int)方法的另一次调用正在进行时调用此方法，
     * 则它将首先阻塞，直到另一个操作完成。</p>
     *
     * @param  block  If <tt>true</tt> then this channel will be placed in
     *                blocking mode; if <tt>false</tt> then it will be placed
     *                non-blocking mode
     *
     * @return  This selectable channel
     *
     * @throws  ClosedChannelException
     *          If this channel is closed
     *
     * @throws  IllegalBlockingModeException
     *          If <tt>block</tt> is <tt>true</tt> and this channel is
     *          registered with one or more selectors
     *
     * @throws IOException
     *         If an I/O error occurs
     */
    public abstract SelectableChannel configureBlocking(boolean block)
        throws IOException;
    //
    // sync(regLock) {
    //   sync(keySet) { throw IBME if block && isRegistered; }
    //   change mode;
    // }

    /**
     * 告诉此通道上的每个I/O操作在完成之前是否都会阻塞。
     * 新创建的通道始终处于阻塞模式。
     *
     * <p> 如果关闭此通道，则不指定此方法返回的值。 </p>
     *
     * @return <tt>true</tt> if, and only if, this channel is in blocking mode
     */
    public abstract boolean isBlocking();

    /**
     * 检索configureBlocking和register方法所基于的对象同步。
     * 这个在需要短期维护特定块模式的适配器的实现中通常很有用。
     *
     * @return  The blocking-mode lock object
     */
    public abstract Object blockingLock();

}
